﻿

using HBase;
using HBase.db;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq; 

namespace hCommand
{
    /**
    *┌────────────────────────────────────────────────┐
    *│　描    述：TransferConfigFacade                                                    
    *│　作    者：sgj                                              
    *│　版    本：1.0                                              
    *│　创建时间：2020/10/10 10:12:05                        
    *└────────────────────────────────────────────────┘
    **/
    public class PathFacade {
       
        private static List<Type> taskList = new List<Type>();
       private static List<String> taskNameList = new List<String>();
        private static Dictionary<String ,Type> taskDict = new Dictionary<String ,Type>();
        public static Type robotType;

        public static void register<T>() where T : BaseTask {
            Type t = typeof(T);
            foreach( var v in taskList ) {
                if( v == t ) {
                    return;
                }
            }
            taskList.Add(t);
            String name = t.Name;
            taskNameList.Add(name);
            taskDict.Add(name ,t);
     
        }

     
        public static List<Type> getAllTaskType() {
            return taskList;
        }

        public static Type getType(String name) {
            if( taskDict.ContainsKey(name) ) {
                return taskDict[name];
            } else {
                throw new Exception("设备类型没有注册" + name);
            }

        } 
        private static object lockObj = new object();
        private static void clearTmp() {
            List<Node> allDict = MyCache.getList<Node>();
            foreach( var v in allDict ) {
                v.clearTmp();
            }
        }

     
        

        private static List<TaskDto> getTaskDtoList(CoreTaskParam p) {
            List<TaskDto> keyList = null;
            if( p.status >= ( int ) CoreTaskParamStatus.待执行 && p.status < ( int ) CoreTaskParamStatus.执行结束 ) {
                keyList = getTaskPath(p.cStn ,p.cDes ,p.cName,0);
                keyList[0].initStatus = ( CoreTaskParamStatus ) p.status;
                if( p.cDes != p.des ) {
                    keyList.AddRange(getTaskPath(p.cDes ,p.des ,null,0));
                }
            } else {
                keyList = getTaskPath(p.cStn ,p.des ,null, 0);
            }

            if( keyList == null || keyList.Count == 0 ) {
                String info = p.src + "到" + p.des + "路径失败";
                LoggerCommon.fileAll(0, info);
                throw new Exception(info);
            }
            //String info2 = p.taskNo + "任务数量"+ keyList.Count;
           // LoggerCommon.consol(0, info2);
            return keyList;
        }



        private static Estimate setTaskDto(BaseTask task, TaskDto taskDto ,Estimate before) {
            List<Node> list = taskDto.list;
            long conmonBeforeTime = 0;
            if( before != null ) {//中间任务的起始地址
                Node b =  before.getNode();
                conmonBeforeTime = b.getEdgeTime(list[0]);
                before.setConmonNextTime(conmonBeforeTime);
            }

            for( int i = 0;i < list.Count;i++ ) {
                Node node = list[i];
                Estimate estimate = node.getEstimate(task.taskNo);
                if( estimate == null ) {
                    conmonBeforeTime = before != null ? before.getConmonNextTime() : 0;
                    estimate = new Estimate(task ,node ,conmonBeforeTime ,node.getR(), taskDto);
                    estimate.addBefore(before);
                }
                if( i != list.Count - 1 ) {
                    estimate.setConmonNextTime(node.getEdgeTime(list[i + 1]));
                }

                before = estimate;

            }
            return before;
        }



        public static bool isArived(int begin ,int end ,String className,int angle) {
            lock( lockObj ) {
                clearTmp();
                Node beginNode = Node.getConfig(begin ,true);
                Node endNode = Node.getConfig(end ,true);
                if( endNode == beginNode ) {//移库或者移缓存
                    return true;
                }
                beginNode.setTmpBeforDistance(DateTime.Now.Ticks, angle);

                findStn(beginNode,className,angle, null);
                return endNode.isArived();
            }
        }

       

        public static long getTime(int begin, int end, String className,int angle) {
            lock (lockObj) {
                clearTmp();
                Node beginNode = Node.getConfig(begin, true);
                Node endNode = Node.getConfig(end, true);
                if (endNode == beginNode) {//移库或者移缓存
                    return 0;
                }
                beginNode.setTmpBeforDistance(DateTime.Now.Ticks, angle);

                findStn(beginNode, className, angle,null);
                if (endNode.isArived()) {
                    return endNode.getArivedTime();
                }
                return -1;
            }
        }


      public static  void add2Src(int pos,int des,BaseTask bt,int angle) {

            CoreTaskParam taskParam = MyCache.queryUnique<CoreTaskParam>((a) => {
                return a.id == bt.completeParamId;
            }, "空跑任务 参数" + bt.completeParamId);

            List<TaskDto> keyList = getTaskPath(pos, des, null, angle);
            CoreTask tc = MyCache.queryUnique<CoreTask>((a) => {
                return a.id == bt.completeId;
            }, "空跑任务" + bt.completeParamId);
            createTaskCache(keyList, taskParam, tc);
        }

        private static List<TaskDto> getTaskPath(int begin ,int end ,String className,int angle) {
            lock( lockObj ) {
                clearTmp();
                Node beginNode = Node.getConfig(begin ,true);
                Node endNode = Node.getConfig(end ,true);
                if( endNode == beginNode ) {//移库或者移缓存
                    TaskDto taskDto = new TaskDto(endNode);
                    taskDto.src = begin;
                    taskDto.addNode(beginNode);
                    Edge tmp = beginNode.getEdge(beginNode); 
                    taskDto.driveType = getType(tmp.driveType);
                    return new List<TaskDto>() { taskDto };
                }
                beginNode.setTmpBeforDistance (DateTime.Now.Ticks+ beginNode.getPredictTime(), angle);
                findStn(beginNode, className, angle,null);
                if( !endNode.isArived() ) {
                    return null;
                }
                List<TaskDto> res = getbefore(endNode ,begin);

                return res;
            }
        }



        private static List<TaskDto> getbefore(Node me ,int begin) {
            List<TaskDto> taskDtoList = new List<TaskDto>();
            TaskDto taskDto = new TaskDto(me);
            NodeAngle na= me.getBastNodeAngle();
            do {
                Node end = na.node;
                
                me = na.before;
                na = me.getTmpBefore(na.beforAngle);
                taskDto.addNode(me);
                var e = me.getEdge( end);
                Type newType = getType(e.driveType) ;
                if(taskDto.driveType == null ) {
                    taskDto.driveType = newType;
                  
                } else if( taskDto.driveType != newType ) {
                    taskDto.src = (int)end.lastNodeId;
                    taskDtoList.Add(taskDto);
                    taskDto = new TaskDto(end);
                    taskDto.addNode(me);
                    taskDto.driveType = newType;
                }
                if( me.isKeyStn ) {
                    taskDto.src = (int)me.lastNodeId;
                    taskDtoList.Add(taskDto);
                    taskDto = new TaskDto(me);
                } else if( me.isConfig(begin) ) {
                    taskDto.src = (int)me.lastNodeId;
                    taskDtoList.Add(taskDto);
                }
            } while( !me.isConfig(begin) );
            taskDtoList.Reverse();
            
            return taskDtoList;
        }

   

        private static void findStn(Node begin, String className,int angle, Node ignore) {//递归找最短路径
            List<Edge> nexts = begin.getNextEdge();
            foreach(Edge edge in nexts ) {
                if (className!=null&& edge.driveType != className) {
                    continue;
                }
                Node des = edge.getDes();
                if (des == ignore) {
                    continue;
                }
                long dis = begin.getTmpBeforDistance(angle);
                DateTime dt = des.getFreeTime(new DateTime(dis) ,null);
                dis = dt.Ticks + edge.R * 10000L + des.getPredictTime()+edge.getTurnRoundTime(angle);
                bool added= des.addNodeAngle(edge.angle, dis, edge.srcNode, angle);

                if (added) { 
                    findStn(des, className, edge.angle, begin);
                }

            }
        }

        public  static Object myOrderLock = new Object();


        public static bool splitParam(CoreTaskParam p ,CoreTask tc) {
           clearParamSplitData(p);
            if( p.status <= ( int ) CoreTaskParamStatus.删除 || p.cDes == p.des && p.status == ( int ) CoreTaskParamStatus.执行结束 || p.status == ( int ) CoreTaskParamStatus.执行完成 ) {
                return false;
            }
            //LoggerCommon.consoleOnly(InfoCode.consle_Split_task,"分解任务" + JsonUtil.mySerializeObject(p));
            lock( myOrderLock ) {
                if( p.type == ( int ) TaskParamType.机器人分解 ) {
                    createTask(p ,tc ,robotType ,null ,CoreTaskParamStatus.待执行,null);
                    return true;
                } else {
                    if( !I18nConfig.isLoc(p.src) && I18nConfig.isLoc(p.des) && I18nConfig.isLoc(p.cStn) ) {// 入库 但是实际位置不是目标位置
                        return false;
                    }
                    List<TaskDto> keyList = getTaskDtoList(p);
                   
                    createTaskCache(keyList, p, tc);
                    return true;
                }
            }
        }
        private static void createTaskCache(List<TaskDto> keyList, CoreTaskParam p, CoreTask tc) {
            lock (BaseTask.obj) {
                BaseTask before = null;
                Estimate beforeEstimate = null;
                for (int i = 0; i < keyList.Count; i++) {
                    TaskDto edge = keyList[i];
                  
                    BaseTask tasks = createTask(p, tc, edge.driveType, edge, edge.initStatus,keyList);

                    beforeEstimate = setTaskDto(tasks, edge, beforeEstimate);
                    if (before != null) {
                        tasks.relyTask.Add(before.getId());
                    }

                    before = tasks;
                }
            }
        }



        private static BaseTask createTask(CoreTaskParam p ,CoreTask tc ,Type t ,TaskDto dto ,CoreTaskParamStatus initStatus,List<TaskDto> keyList) {
            BaseTask task = ( BaseTask ) Activator.CreateInstance(t);
            task.taskNo = p.taskNo;
            task.initBase(tc ,p ,dto,keyList);
            task.status = (short)initStatus;
            task.id = task.taskNo * 1000000L + task.src;
            task.priority = tc.priority;
            //LoggerCommon.consol(1, task.className + "生成任务" + task.taskNo+"-"+task.getId());
            MyCache.addOver(task);
            List<long> relys = p.getRelay();
       
            List<Type> list = getAllTaskType();
            foreach (Type ta in list) {
                List<BaseTask> li = MyCache.getList<BaseTask>(ta);
                foreach (var t1 in li) {
                    if (relys.Contains(t1.completeParamId)) {
                        task.relyTask.Add(t1.getId());
                    }
                }
            }

            return task;
        }
        

        public static void clearParamSplitData(CoreTaskParam p) {

            Node n = Node.getConfig(p.des);
            Estimate e = n.getTaskEstimate(p.taskNo);
            if (e != null) {
                e.removeBefore();
                n.clearCurrent(e.getId());

            }
            long paramId = p.id;
            List<Type> list = getAllTaskType();
            List<BaseTask> res = new List<BaseTask>();
            foreach( Type t in list ) {
                List<BaseTask> li = MyCache.getList<BaseTask>(t);
                IEnumerable<CacheData> res1 = li.Where((a) => {
                    return a.completeParamId == paramId;
                });
                foreach( var k in res1 ) {
                    MyCache.remove(k);

                }

            }
        }

        public static void removeComplete(long id) {
            List<CoreTaskParam> paramList = MyCache.query<CoreTaskParam>((a) => {
                return a.taskId == id;
            });
            foreach( var p in paramList ) {
                removeParam(p); 

            }
        }


        public static void removeParam(CoreTaskParam p) {
            LoggerCommon.fileAll(0,"清楚缓存"+p.taskNo);
            clearParamSplitData(p);
                MyCache.remove(p); 
        }



        public static BaseTask getTaskById(long id) {

            List<Type> list = getAllTaskType();
            foreach( Type t in list ) {
                List<BaseTask> li = MyCache.getList<BaseTask>(t);
                foreach( var t1 in li ) {

                    if( t1.getId() == id ) {
                        return t1;
                    }
                }
            }

            return null;
        }
       



         
    }
}
